package com.xingda.packing.aspect;

import com.alibaba.fastjson.JSONObject;
import com.xingda.packing.annotation.OpLog;
import com.xingda.packing.common.R;
import com.xingda.packing.config.ThreadLocalConfig;
import com.xingda.packing.http.WxLoginHttp;
import com.xingda.packing.minitor.dto.UserInfo;
import com.xingda.packing.minitor.entity.PkLog;
import com.xingda.packing.minitor.mapper.PkLogMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Objects;

@Aspect
@Component
@Slf4j
public class OpAspect implements ApplicationContextAware {
    private final HashMap<String, Object> hashMap = new HashMap<>();
    private ApplicationContext applicationContext;
    private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
    @Resource
    private ThreadLocalConfig threadLocalConfig;
    @Resource
    private PkLogMapper pkLogMapper;

    @Override
    public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Pointcut("@annotation(com.xingda.packing.annotation.OpLog)")
    public void aspect() {
    }

    @AfterThrowing(value = "aspect()")
    public void error() {
        UserInfo userInfo = threadLocalConfig.get();
        PkLog pkLog = new PkLog();
        pkLog.setUsername(userInfo.getRealname());
        pkLog.setNumber(userInfo.getUsername());
        pkLog.setIsSuccess(0);
        pkLog.setCreateTime(new Date());
        pkLog.setOperation(userInfo.getOperation());
        pkLog.setCompany(userInfo.getCompany());
        pkLogMapper.insert(pkLog);
    }

    @Around("aspect()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        getParams(joinPoint);
        //参数校验
        if (Objects.isNull(hashMap.get("username")) || Objects.isNull(hashMap.get("corp")) || Objects.isNull(hashMap.get("veri"))) {
            return R.error("请输入人事编号|公司编号|微信验证码");
        }
        String operation = hashMap.get("opitem") + ":" + hashMap.get("param");
        if (hashMap.get("username").equals("admin")) {
            threadLocalConfig.set(new UserInfo("测试账号", "管理员", "苏州智殷", operation));
        } else {
            //信息中心校验
            JSONObject jsonObject = WxLoginHttp.wxLogin(hashMap.get("username").toString(), hashMap.get("corp").toString(), hashMap.get("veri").toString());
            if (Objects.nonNull(jsonObject) && jsonObject.getBoolean("state")) {
                JSONObject data = jsonObject.getJSONObject("data");
                String realname = data.getString("realname");
                threadLocalConfig.set(new UserInfo(realname, hashMap.get("username").toString(), hashMap.get("corp").toString(), operation));
            } else {
                return R.error(jsonObject.getString("msg"));
            }
        }
        return joinPoint.proceed();
    }

    private void getParams(JoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        OpLog opLog = method.getAnnotation(OpLog.class);
        StandardEvaluationContext context = new StandardEvaluationContext();
        // 设置bean的根对象
        context.setBeanResolver(new BeanFactoryResolver(applicationContext));
        // 获取被拦截方法的参数信息
        String[] params = parameterNameDiscoverer.getParameterNames(method);
        // 把参数配置到上下文中
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            assert params != null;
            context.setVariable(params[i], args[i]);
        }
        // 创建spel的解析对象
        SpelExpressionParser parser = new SpelExpressionParser();
        String username = parser.parseExpression(opLog.username()).getValue(context, String.class);
        String corp = parser.parseExpression(opLog.corp()).getValue(context, String.class);
        String veri = parser.parseExpression(opLog.veri()).getValue(context, String.class);
        String param;
        if (opLog.param().equals("all")) {
            param = "all";
        } else {
            param = parser.parseExpression(opLog.param()).getValue(context, String.class);
        }
        hashMap.put("username", username);
        hashMap.put("corp", corp);
        hashMap.put("veri", veri);
        hashMap.put("opitem", opLog.opItem());
        hashMap.put("param", param);
    }
}
